package dk.rafaelcouto.PhoneTone_Extractor;

public class DtmfDetector
{
    protected static final int COEFF_NUMBER = 18;
    protected static final short[] CONSTANTS;
    public static final int NUMBER_OF_BUTTONS = 65;
    protected final int SAMPLES;
    protected int[] T;
    protected int dialTonesToOhersDialTones;
    protected int dialTonesToOhersTones;
    protected final int frameSize;
    protected int frame_count;
    private short indexForDialButtons;
    protected short[] internalArray;
    protected short[] pArraySamples;
    private char[] pDialButtons;
    protected boolean permissionFlag;
    protected int powerThreshold;
    protected char prevDialButton;
    
    static {
        CONSTANTS = new short[] { 27860, 26745, 25529, 24216, 19747, 16384, 12773, 8967, 21319, 29769, 32706, 32210, 31778, 31226, -1009, -12772, -22811, -30555 };
    }
    
    public DtmfDetector(final int frameSize) {
        this.pDialButtons = new char[65];
        this.indexForDialButtons = 0;
        this.T = new int[18];
        this.SAMPLES = 102;
        this.powerThreshold = 328;
        this.dialTonesToOhersTones = 16;
        this.dialTonesToOhersDialTones = 6;
        this.frameSize = frameSize;
        this.pDialButtons[0] = '\0';
        this.pArraySamples = new short[102 + this.frameSize];
        this.internalArray = new short[102];
        this.frame_count = 0;
        this.prevDialButton = ' ';
        this.permissionFlag = false;
    }
    
    public void dtmfDetecting(final short[] array) {
        for (int i = 0; i < this.frameSize; ++i) {
            this.pArraySamples[i + this.frame_count] = array[i];
        }
        this.frame_count += this.frameSize;
        final int frame_count = this.frame_count;
        int n = 0;
        if (frame_count >= 102) {
            while (this.frame_count >= 102) {
                char prevDialButton;
                if (n == 0) {
                    prevDialButton = this.dtmfDetection(this.pArraySamples);
                }
                else {
                    final short[] array2 = new short[this.pArraySamples.length - n];
                    for (int j = 0; j < this.pArraySamples.length - n; ++j) {
                        array2[j] = this.pArraySamples[n + j];
                    }
                    prevDialButton = this.dtmfDetection(array2);
                }
                if (this.permissionFlag) {
                    if (prevDialButton != ' ') {
                        final char[] pDialButtons = this.pDialButtons;
                        final short indexForDialButtons = this.indexForDialButtons;
                        this.indexForDialButtons = (short)(indexForDialButtons + 1);
                        pDialButtons[indexForDialButtons] = prevDialButton;
                        this.pDialButtons[this.indexForDialButtons] = '\0';
                        if (this.indexForDialButtons >= 64) {
                            this.indexForDialButtons = 0;
                        }
                    }
                    this.permissionFlag = false;
                }
                if (prevDialButton != ' ' && this.prevDialButton == ' ') {
                    this.permissionFlag = true;
                }
                this.prevDialButton = prevDialButton;
                n += 102;
                this.frame_count -= 102;
            }
            for (int k = 0; k < this.frame_count; ++k) {
                this.pArraySamples[k] = this.pArraySamples[k + n];
            }
        }
    }
    
    protected char dtmfDetection(final short[] array) {
        short norm_l = 32;
        char c = ' ';
        short n = 0;
        for (int i = 0; i < 102; ++i) {
            if (array[i] >= 0) {
                n += array[i];
            }
            else {
                n -= array[i];
            }
        }
        if (n / 102 < this.powerThreshold) {
            return ' ';
        }
        for (int j = 0; j < 102; ++j) {
            this.T[0] = array[j];
            if (this.T[0] != 0 && norm_l > this.norm_l(this.T[0])) {
                norm_l = this.norm_l(this.T[0]);
            }
        }
        final short n2 = (short)(norm_l - 16);
        for (int k = 0; k < 102; ++k) {
            this.T[0] = array[k];
            this.internalArray[k] = (short)(this.T[0] << n2);
        }
        this.goertzelFilter(DtmfDetector.CONSTANTS[0], DtmfDetector.CONSTANTS[1], this.internalArray, this.T, 102, 0);
        this.goertzelFilter(DtmfDetector.CONSTANTS[2], DtmfDetector.CONSTANTS[3], this.internalArray, this.T, 102, 2);
        this.goertzelFilter(DtmfDetector.CONSTANTS[4], DtmfDetector.CONSTANTS[5], this.internalArray, this.T, 102, 4);
        this.goertzelFilter(DtmfDetector.CONSTANTS[6], DtmfDetector.CONSTANTS[7], this.internalArray, this.T, 102, 6);
        this.goertzelFilter(DtmfDetector.CONSTANTS[8], DtmfDetector.CONSTANTS[9], this.internalArray, this.T, 102, 8);
        this.goertzelFilter(DtmfDetector.CONSTANTS[10], DtmfDetector.CONSTANTS[11], this.internalArray, this.T, 102, 10);
        this.goertzelFilter(DtmfDetector.CONSTANTS[12], DtmfDetector.CONSTANTS[13], this.internalArray, this.T, 102, 12);
        this.goertzelFilter(DtmfDetector.CONSTANTS[14], DtmfDetector.CONSTANTS[15], this.internalArray, this.T, 102, 14);
        this.goertzelFilter(DtmfDetector.CONSTANTS[16], DtmfDetector.CONSTANTS[17], this.internalArray, this.T, 102, 16);
        int n3 = 0;
        int n4 = 0;
        for (int l = 0; l < 4; ++l) {
            if (n4 < this.T[l]) {
                n3 = l;
                n4 = this.T[l];
            }
        }
        int n5 = 4;
        int n6 = 0;
        for (int n7 = 4; n7 < 8; ++n7) {
            if (n6 < this.T[n7]) {
                n5 = n7;
                n6 = this.T[n7];
            }
        }
        int n8 = 0;
        for (int n9 = 0; n9 < 10; ++n9) {
            n8 += this.T[n9];
        }
        int n10 = n8 - this.T[n3] - this.T[n5] >> 3;
        if (n10 == 0) {
            n10 = 1;
        }
        if (this.T[n3] / n10 < this.dialTonesToOhersDialTones) {
            return ' ';
        }
        if (this.T[n5] / n10 < this.dialTonesToOhersDialTones) {
            return ' ';
        }
        if (this.T[n3] < this.T[n5] >> 2) {
            return ' ';
        }
        if (this.T[n5] < (this.T[n3] >> 1) - (this.T[n3] >> 3)) {
            return ' ';
        }
        for (int n11 = 0; n11 < 18; ++n11) {
            if (this.T[n11] == 0) {
                this.T[n11] = 1;
            }
        }
        for (int n12 = 10; n12 < 18; ++n12) {
            if (this.T[n3] / this.T[n12] < this.dialTonesToOhersTones) {
                return ' ';
            }
            if (this.T[n5] / this.T[n12] < this.dialTonesToOhersTones) {
                return ' ';
            }
        }
        for (int n13 = 0; n13 < 10; ++n13) {
            if (this.T[n13] != this.T[n5] && this.T[n13] != this.T[n3]) {
                if (this.T[n3] / this.T[n13] < this.dialTonesToOhersDialTones) {
                    return ' ';
                }
                if (n5 != 4) {
                    if (this.T[n5] / this.T[n13] < this.dialTonesToOhersDialTones) {
                        return ' ';
                    }
                }
                else if (this.T[n5] / this.T[n13] < this.dialTonesToOhersDialTones / 3) {
                    return ' ';
                }
            }
        }
        Label_0732: {
            switch (n3) {
                case 0: {
                    switch (n5) {
                        default: {
                            break Label_0732;
                        }
                        case 4: {
                            c = '1';
                            break Label_0732;
                        }
                        case 5: {
                            c = '2';
                            break Label_0732;
                        }
                        case 6: {
                            c = '3';
                            break Label_0732;
                        }
                        case 7: {
                            c = 'A';
                            break Label_0732;
                        }
                    }
                    
                }
                case 1: {
                    switch (n5) {
                        default: {
                            break Label_0732;
                        }
                        case 4: {
                            c = '4';
                            break Label_0732;
                        }
                        case 5: {
                            c = '5';
                            break Label_0732;
                        }
                        case 6: {
                            c = '6';
                            break Label_0732;
                        }
                        case 7: {
                            c = 'B';
                            break Label_0732;
                        }
                    } 
                }
                case 2: {
                    switch (n5) {
                        default: {
                            break Label_0732;
                        }
                        case 4: {
                            c = '7';
                            break Label_0732;
                        }
                        case 5: {
                            c = '8';
                            break Label_0732;
                        }
                        case 6: {
                            c = '9';
                            break Label_0732;
                        }
                        case 7: {
                            c = 'C';
                            break Label_0732;
                        }
                    }
                    
                }
                case 3: {
                    switch (n5) {
                        default: {
                            break Label_0732;
                        }
                        case 4: {
                            c = '*';
                            break Label_0732;
                        }
                        case 5: {
                            c = '0';
                            break Label_0732;
                        }
                        case 6: {
                            c = '#';
                            break Label_0732;
                        }
                        case 7: {
                            c = 'D';
                            break Label_0732;
                        }
                    }
                    
                }
            }
        }
        return c;
    }
    
    public char[] getDialButtonsArray() {
        return this.pDialButtons;
    }
    
    public int getIndexDialButtons() {
        return this.indexForDialButtons;
    }
    
    protected void goertzelFilter(final short n, final short n2, final short[] array, final int[] array2, final int n3, final int n4) {
        int n5 = 0;
        int n6 = 0;
        int n7 = 0;
        int n8 = 0;
        for (int i = 0; i < n3; i = (short)(i + 1)) {
            final int n9 = this.mpy48sr(n, n5 << 1) - n6 + array[i];
            final int n10 = this.mpy48sr(n2, n7 << 1) - n8 + array[i];
            n6 = n5;
            n8 = n7;
            n5 = n9;
            n7 = n10;
        }
        final int n11 = n5 >> 10;
        final int n12 = n7 >> 10;
        final int n13 = n6 >> 10;
        final int n14 = n8 >> 10;
        final int mpy48sr = this.mpy48sr(n, n11 << 1);
        final int mpy48sr2 = this.mpy48sr(n2, n12 << 1);
        final short n15 = (short)((short)mpy48sr * (short)n13);
        final short n16 = (short)((short)mpy48sr2 * (short)n14);
        final short n17 = (short)((short)n11 * (short)n11 + (short)n13 * (short)n13 - n15);
        final short n18 = (short)((short)n12 * (short)n12 + (short)n14 * (short)n14 - n16);
        array2[n4] = n17;
        array2[n4 + 1] = n18;
    }
    
    protected int mpy48sr(final short n, final int n2) {
        return (16384 + n * (char)n2 >> 15) + (n * (short)(n2 >> 16) << 1);
    }
    
    short norm_l(int i) {
        short n;
        if (i == 0) {
            n = 0;
        }
        else {
            if (i == -1) {
                return 31;
            }
            if (i < 0) {
                i ^= -1;
            }
            for (n = 0; i < 1073741824; i <<= 1, ++n) {}
        }
        return n;
    }
    
    public void zerosIndexDialButtons() {
        this.indexForDialButtons = 0;
    }
}
